home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / libs / knowhow4 / gbuf.cpp < prev    next >
C/C++ Source or Header  |  1994-10-10  |  24KB  |  696 lines

  1. #include <stdlib.h>
  2. #include "gbuf.h"
  3. #include "move.h"
  4. #include "imagebuf.h"
  5.  
  6. #include <string.h>
  7.  
  8. int s_max_color(int bitpx, int nplanes)   // Return max color in image
  9.     {
  10.     int src_max_color;
  11.     switch(bitpx)
  12.     {
  13.     case 8: src_max_color = 255; break;
  14.     case 2: src_max_color = 3; break;
  15.     case 1:
  16.         src_max_color = (nplanes == 1) ? 1 : 15; break;
  17.     }
  18.     return src_max_color;
  19.     }
  20. /////////////////////////////
  21. int get_color_mult(int src_max_color, int dest_max_color) // color scaling
  22.     {                                                     // if modes are
  23.     if(dest_max_color >= src_max_color)                   // incompatible
  24.     return dest_max_color / src_max_color;
  25.     return src_max_color / dest_max_color;
  26.     }
  27. ///////////////////////////
  28. inline int bw_pix(int color, int x, int y)            // Transform color pix
  29.     {                                                 // to B/W using pattern
  30.     int sx = x % 8;                                   // We suppose that 1st
  31.     int sy = y % 8;                                   // 16 patterns approxi-
  32.     return (pattern[color][sy]) & (1 << sx) ? 1 : 0;  // mates 16 colors
  33.     }
  34. ////////////////////////
  35. int image_size(int width, int height, int bitpx, int nplanes) // BGI imagesize
  36.     {                                                         // works incor-
  37.     return ((width * bitpx + 7) >> 3) * nplanes * height;     // rect
  38.     }
  39. ////////////////////////
  40. GrafBuffer::GrafBuffer(loc dim, char* swapName, rect sa, int bpx, int np)
  41.     {
  42.     loaded = 0;                                  // Buffer is not cleared
  43.     buf_dim = dim;                               // Buffer dimentions, pixels
  44.     file_name = strdup(swapName);                // Swap file
  45.  
  46.     loc disp(bpx, np);                              // Display bpx and nplanes
  47.     bitpx = disp.X;                              // Bit per pixel
  48.     nplanes = disp.Y;                            // Number of planes
  49.  
  50.     bound_size.X = buf_dim.X;                    // Bound is swap area in memory
  51.     bound_size.Y = BOUND_SIZE / image_size(dim.X, 1, bitpx, nplanes);           // calculation of bound size
  52.  
  53.     FILE* Buf = fopen(file_name, "w+b");         // Buffer file, create it and
  54.     fclose(Buf);                                 // immediately close
  55.  
  56.     screen_area = sa;                 // Screen area (viewport)
  57.     screen_position = rect(0, 0, sa.width() - 1, sa.height() - 1);
  58.     image = NULL;                                // Keeps the bound
  59.     }
  60. ///////////////////////
  61. void GrafBuffer::clear()
  62.     {
  63.     rewind(buffer);
  64.     long len = imagesize();
  65.     for(long i = 0; i < len; i++)
  66.     fputc(255, buffer);
  67.     loaded = 1;                     // Image allocated on disk
  68.     }
  69. ///////////////////////
  70. int GrafBuffer::b_open()     // Open swap file (created by constructor)
  71.     {
  72.     if(!(image = (imageP)malloc(BOUND_SIZE + sizeof(imageP))))
  73.     return 0;
  74.     buffer = fopen(file_name, "r+b");
  75.     image->xmax = bound_size.X - 1;
  76.     image->ymax = bound_size.Y - 1;
  77.     return 1;
  78.     }
  79. ///////////////////////
  80. void GrafBuffer::b_close()    // Close swap file
  81.     {
  82.     fclose(buffer);
  83.     delete image;
  84.     image = NULL;
  85.     }
  86. ///////////////////////
  87. long GrafBuffer::imagesize()
  88.     {
  89.     long size = image_size(buf_dim.X, 1, bitpx, nplanes) - sizeof(imageP);
  90.     size *= buf_dim.Y;
  91.     return size;
  92.     }
  93. ///////////////////////
  94. void GrafBuffer::buffer_disk(rect src, char* name)
  95.     {
  96.     FILE* work;
  97.     work = fopen(name, "w+b");
  98.  
  99.     int end_bound = src.corner.Y / bound_size.Y + 1;  // lower bound
  100.     int start_bound = src.origin.Y / bound_size.Y;    // upper bound
  101.  
  102.     for(int i = start_bound; i < end_bound; i++)      // for b. involved
  103.     {
  104.     get_bound(i);                                 // Read bound from disk
  105.  
  106.     int s_y = (i > start_bound) ? 0               // y coord inside image
  107.           : src.origin.Y - i * bound_size.Y;
  108.     int e_y = (i < end_bound - 1) ? bound_size.Y - 1
  109.           : src.corner.Y - i * bound_size.Y;
  110.     int image_x = image->xmax;                    // We intend to cut
  111.     int image_y = image->ymax;                    // image and need reserv
  112.  
  113.     cut_image(image, rect(0, 0, image->xmax, image->ymax),
  114.         rect(src.origin.X, s_y, image->xmax, image->ymax));
  115.     cut_image(image, rect(0, 0, image->xmax, image->ymax),
  116.         rect(0, 0, src.corner.X - src.origin.X, e_y));
  117.  
  118.     fwrite(image->data, image_size(src.width(), e_y - s_y + 1,
  119.          bitpx, nplanes), 1, work);
  120.     image->xmax = image_x;
  121.     image->ymax = image_y;
  122.     }
  123.     fclose(work);
  124.     }
  125. //////////////////////
  126. void GrafBuffer::get_BW(int number)
  127.     {
  128.     int plane_size = (bound_size.X + 7) >> 3;    // size of plane
  129.     int scan_size = plane_size << 2;             // size of scan line
  130.     imageP work =
  131.         (imageP)malloc(scan_size + sizeof(imageP)); // bitpx, nplanes));
  132.     work->xmax = bound_size.X - 1;               // We construct one-line
  133.     work->ymax = 0;                              // "work" image; "image"
  134.     image->ymax = (bound_size.Y - 1) << 2;       // was color, "work" - BW
  135.     int size = plane_size * bound_size.Y;        // size of one (of 4) bounds
  136.     int i, j, x;                                 // image(COL)->work(BW)->image(BW)
  137.     ImageBuffer im;                              // Buffer for 8 pixels of byte
  138.     int vert_sh = bound_size.Y * number;         // Offset in "buffer" file
  139.     fseek(buffer, (long)(number) * size * 4, SEEK_SET);
  140.     for(i = 0; i < 4; i++)                              // For 4 planes
  141.     {
  142.     for(j = 0; j < bound_size.Y; j++)               // For all scan lines
  143.         {
  144.         fread(work->data, scan_size, 1, buffer);
  145.         for(x = 0; x < plane_size; x++)             // For plane
  146.         {
  147.         unsigned char pix = im.image_get_pixel(work, x,
  148.             vert_sh + j);
  149.         image->data[x + i * size + j * plane_size] = pix;
  150.         }
  151.         }
  152.     }
  153.     delete work;
  154.     }
  155. //////////////////////
  156. imageP GrafBuffer::get_bound(int number)     // get number-th bound, from 0
  157.     {
  158.     int size = image_size(bound_size.X, bound_size.Y, bitpx, nplanes);
  159.     fseek(buffer, (long)number * size, SEEK_SET);
  160.     fread(image->data, size, 1, buffer);
  161.     return image;
  162.     }
  163. //////////////////////
  164. void GrafBuffer::put_bound(int number)
  165.     {
  166.     int size = image_size(bound_size.X, bound_size.Y, bitpx, nplanes);
  167.     fseek(buffer, (long)number * size, SEEK_SET);
  168.     fwrite(image->data, size, 1, buffer);
  169.     }
  170. //////////////////////
  171. void GrafBuffer::bound_screen(int number, loc comp_s, loc comp_d)
  172.     {
  173.     if(bound_size.Y * (number + 1) < screen_position.origin.Y  // If this bound
  174.     || bound_size.Y * number >= screen_position.corner.Y)  // is invisible
  175.     return;
  176.     image = get_bound(number);  // Read this bound
  177.  
  178.     int y1 = (screen_position.origin.Y > number * bound_size.Y) // screen
  179.          ? screen_area.origin.Y
  180.            : screen_area.origin.Y
  181.              + (long)(number * bound_size.Y
  182.              - screen_position.origin.Y) * comp_d.Y / comp_s.Y;
  183.  
  184.     int y3 = (screen_position.origin.Y > number * bound_size.Y)
  185.          ? screen_position.origin.Y - number * bound_size.Y - 1 : 0;
  186.  
  187.     int y4 = (screen_position.corner.Y < (number + 1) * bound_size.Y)
  188.          ? screen_position.corner.Y - number * bound_size.Y    // image
  189.            : bound_size.Y;
  190.  
  191.     image_screen(image, rect(screen_position.origin.X, y3,
  192.               screen_position.corner.X, y4),
  193.          loc(screen_area.origin.X, y1),
  194.          bitpx, nplanes,
  195.          comp_s, comp_d);
  196.     }
  197. //////////////////////
  198. void GrafBuffer::screen_bound(int number)
  199.     {
  200.     if(bound_size.Y * (number + 1) < screen_position.origin.Y
  201.     || bound_size.Y * number > screen_position.corner.Y)
  202.     return;
  203.  
  204.     image = get_bound(number);
  205.  
  206.     int y1 = (screen_position.origin.Y > number * bound_size.Y)
  207.          ? screen_area.origin.Y
  208.            : screen_area.origin.Y + number * bound_size.Y
  209.                - screen_position.origin.Y;
  210.     int y2 = (screen_position.corner.Y < (number + 1) * bound_size.Y)
  211.          ? screen_area.corner.Y - 1
  212.            : screen_area.origin.Y + (number + 1) * bound_size.Y
  213.                 - screen_position.origin.Y - 1;
  214.  
  215.     int y3 = (screen_position.origin.Y > number * bound_size.Y)
  216.          ? screen_position.origin.Y - number * bound_size.Y - 1 : 0;
  217.  
  218.     screen_image(image, rect(screen_area.origin.X, y1,
  219.               screen_area.corner.X, y2),
  220.          loc(screen_position.origin.X, y3));
  221.     put_bound(number);
  222.     }
  223. //////////////////////
  224. void GrafBuffer::buffer_screen(loc comp_s, loc comp_d)
  225.     {
  226.     int bound_num = buf_dim.Y / bound_size.Y + 1;
  227.     for(int i = 0; i < bound_num; i++)
  228.     bound_screen(i, comp_s, comp_d);
  229.     }
  230. //////////////////////
  231. void GrafBuffer::buffer_screen(rect temp,    // temp - on screen
  232.            loc comp_s, loc comp_d)
  233.     {
  234.     int start_bound = ((long)(temp.origin.Y - screen_area.origin.Y)
  235.               * comp_s.Y / comp_d.Y + screen_position.origin.Y)
  236.               / bound_size.Y;
  237.     int end_bound = ((long)(temp.corner.Y - screen_area.origin.Y)
  238.               * comp_s.Y / comp_d.Y + screen_position.origin.Y)
  239.               / bound_size.Y + 1;
  240.  
  241.     for(int i = start_bound; i < end_bound; i++)
  242.     {
  243.     image = get_bound(i);
  244.  
  245.     int y1 = ((long)(temp.origin.Y
  246.           - screen_area.origin.Y) * comp_s.Y / comp_d.Y
  247.           + screen_position.origin.Y
  248.             > i * bound_size.Y)          // screen
  249.          ? temp.origin.Y
  250.            : screen_area.origin.Y
  251.              + (long)(i * bound_size.Y
  252.              - screen_position.origin.Y) * comp_d.Y / comp_s.Y;
  253.  
  254.     int y3 = ((long)(temp.origin.Y - screen_area.origin.Y)
  255.         * comp_s.Y / comp_d.Y + screen_position.origin.Y
  256.               > i * bound_size.Y)
  257.          ? screen_position.origin.Y - i * bound_size.Y
  258.              + (long)(temp.origin.Y - screen_area.origin.Y)
  259.              * comp_s.Y / comp_d.Y
  260.              : 0;
  261.  
  262.     int y4 = (screen_position.origin.Y + (temp.corner.Y
  263.           - screen_area.origin.Y) * comp_s.Y / comp_d.Y
  264.             < (i + 1) * bound_size.Y)
  265.          ? screen_position.origin.Y + (long)(temp.corner.Y
  266.            - screen_area.origin.Y) * comp_s.Y / comp_d.Y
  267.                - i * bound_size.Y    // image
  268.            : bound_size.Y;
  269.  
  270.     image_screen(image,
  271.         rect(screen_position.origin.X + (long)(temp.origin.X
  272.         - screen_area.origin.X) * comp_s.X / comp_d.X, y3,
  273.         screen_position.origin.X + (long)(temp.corner.X
  274.         - screen_area.origin.X) * comp_s.X / comp_d.X, y4),
  275.          loc(temp.origin.X, y1),
  276.          bitpx, nplanes,
  277.          comp_s, comp_d, 1);
  278.  
  279.     }
  280.     }
  281. //////////////////////
  282. void GrafBuffer::screen_buffer()
  283.     {
  284.     int bound_num = buf_dim.Y / bound_size.Y + 1;
  285.     for(int i = 0; i < bound_num; i++)
  286.     screen_bound(i);
  287.     }
  288. //////////////////////
  289. void GrafBuffer::scroll(int shift, int direction, int show)
  290.     {
  291.     rect reserv = screen_area;
  292.     rect res = screen_position;
  293.  
  294.     switch(direction)
  295.     {
  296.     case UP:
  297.         if(screen_position.corner.Y + shift > buf_dim.Y)
  298.         return;
  299.  
  300.         screen_position.origin.Y += shift;
  301.         screen_position.corner.Y += shift;
  302.         if(show)
  303.             buffer_screen();
  304.         return;
  305.     case DN:
  306.         if(screen_position.origin.Y - shift < 0)
  307.         return;
  308.         screen_position.origin.Y -= shift;
  309.         screen_position.corner.Y -= shift;
  310.             if(show)
  311.             buffer_screen();
  312.         return;
  313.     case LEFT:
  314.         if(screen_position.corner.X + shift > buf_dim.X)
  315.         return;
  316.         screen_position.origin.X += shift;
  317.         screen_position.corner.X += shift;
  318.         if(show)
  319.                    buffer_screen();
  320.         return;
  321.     case RIGHT:
  322.         if(screen_position.origin.X - shift < 0)
  323.         return;
  324.         screen_position.origin.X -= shift;
  325.         screen_position.corner.X -= shift;
  326.         buffer_screen();
  327.         return;
  328.  
  329.     }
  330.     }
  331. /////////////////////////////
  332. int pcx_file_buffer(GrafBuffer* buf, loc pos, char* name, int col)
  333.     {
  334.     FILE* f;
  335.     if((f = fopen(name, "rb")) == NULL)
  336.     return 0;                       // Open PCX file
  337.     pcxheader p;                        // Read PCX header
  338.     if(!get_pcx_header(f, &p))          // Simple error handler
  339.     {
  340.     fclose(f);
  341.     return 0;
  342.     }
  343.  
  344.     if(p.bitpx == 1 && p.nplanes == 1)          // Trouble: after call to
  345.     {                                       // the pcx_bw_to_col() 8 bit
  346.     fclose(f);                              // rounded image will (possib-
  347.     pcx_bw_to_col(name, "tmp____u.pcz");    // ly) replace 16 bit one. To
  348.     delete name;                            // read new pcx header we need
  349.     name = strdup("tmp____u.pcz");          // additional call to header
  350.  
  351.     if((f = fopen(name, "rb")) == NULL)     // reader function
  352.         return 0;
  353.     get_pcx_header(f, &p);
  354.     }
  355.  
  356.     int bplin; // bytes per line in same buffer if compatible, or in new buffer
  357.  
  358.     int xsize = p.x2 - p.x1 + 1;
  359.     int ysize = p.y2 - p.y1 + 1;
  360.  
  361.     if(pos.X + xsize >= buf->buf_dim.X         // If picture is larger
  362.     || pos.Y + ysize >= buf->buf_dim.Y)    // than buffer - resize
  363.     {                                      // all data will be lost
  364.     buf->b_close();
  365.     buf->bound_size.X = buf->buf_dim.X = pos.X + xsize + 1;
  366.     buf->bound_size.Y =
  367.         (BOUND_SIZE / (::imagesize(0, 0, buf->bound_size.X - 1, 0)
  368.              - sizeof(imageP) - 2));
  369.     if(buf->bound_size.Y > buf->buf_dim.Y)
  370.         buf->bound_size.Y = buf->buf_dim.Y;
  371.  
  372.     buf->buf_dim.Y = pos.Y + p.y2 - p.y1 + 1;
  373.     buf->b_open();
  374.     }
  375.  
  376.     pcxheader work;
  377.     GrafBuffer* work_gb;
  378.  
  379.     int start_bound;
  380.     int end_bound;
  381.     int x;
  382.     int y;
  383.     int start_x;
  384.     int plane_num = p.nplanes - 1;   // number of current plane, cycle variable
  385.  
  386.     if(p.nplanes != buf->nplanes || p.bitpx != buf->bitpx  // if formates are
  387.        || col != 16)
  388.     {                                                  // incompatible
  389.     work_gb =                                          // Create new buffer
  390.         new GrafBuffer(loc((p.x2 - p.x1 + 1 + 7) / 8 * 8,
  391.                             p.y2 - p.y1 + 1),
  392.         "__work.buf", rect(0, 0, 10, 20), p.bitpx, p.nplanes);
  393.     if(!(work_gb->b_open()))       // Not enough memory to open 2-th
  394.         {                      // buffer
  395.         delete work_gb;
  396.         fclose(f);
  397.         return 0;
  398.         }
  399.     bplin = p.bplin;     /* Bytes per line             */
  400.         work_gb->clear();
  401.         start_bound = 0;
  402.         end_bound = (p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1;
  403.         x = plane_num * bplin;  // start x byte in source rectangle
  404.         y = start_x = 0;
  405.     }
  406.     else                               // formates are compatible
  407.     {                // Now we can call it for compatible and incompatible
  408.     work_gb = buf;   // formates
  409.     put_pcx_header(NULL, &work,      // tric to obtain bplin
  410.            loc(buf->bound_size.X, buf->bound_size.Y));  // for "bound" image
  411.     bplin = work.bplin;
  412.         start_bound = pos.Y / work_gb->bound_size.Y;                        // In "old" buffer
  413.         end_bound = (pos.Y + p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1;
  414.         x = pos.X * work_gb->bitpx / 8 + plane_num * bplin;  // start x byte in source rectangle
  415.         y = pos.Y - work_gb->bound_size.Y * start_bound; // start y in current bound
  416.         start_x = (pos.X * work_gb->bitpx + 7) / 8; // start x byte in image
  417.     }
  418.  
  419.     int w_data = work_gb->nplanes * bplin; // length of image line, bytes
  420.     int i = start_bound;
  421.  
  422.     work_gb->get_bound(i);
  423.     int ex = 0;
  424.     buf->loaded = 1;
  425.     while(!ex)
  426.     {
  427.     int count = 1;                         // PCX counter
  428.     unsigned char ch = fgetc(f);           // read char
  429.     if((ch & 0xC0 ) == 0xC0)                 // if two upper bits == 1
  430.         {
  431.         count = 63 & ch;                   // use 6 low bits as counter
  432.         ch = fgetc(f);                     // read the pattern
  433.         }
  434.     for(int j = 0; j < count; j++)
  435.         {
  436.         unsigned char ch1;
  437.         ch1 = work_gb->image->data[x + w_data * y];
  438.         work_gb->image->data[x + w_data * y] = ch;
  439.         x++;
  440.         if(x == bplin * plane_num + start_x + p.bplin)
  441.         {
  442.         work_gb->image->data[x + w_data * y - 1] =
  443.             (ch    & (255 << xsize % 8))
  444.             | ((255 >> (8 - xsize % 8) & ch1));
  445.  
  446.                      // If end of scan line or end of plane
  447.         if(plane_num == 0)   // If end of scan line
  448.             {
  449.             plane_num = work_gb->nplanes - 1;
  450.             x = start_x + plane_num * bplin;
  451.  
  452.             if(y + 1 < work_gb->bound_size.Y
  453. /* ! */            && i * work_gb->bound_size.Y + y + 1 < pos.Y + ysize)
  454.             y++;
  455.             else
  456.             {
  457.             work_gb->put_bound(i);
  458.             i++;
  459.             if(i < end_bound)
  460.                 {
  461.                 work_gb->get_bound(i);
  462.                 y = 0;
  463.                 }
  464.             else                   // Exit loop
  465.                 {
  466.                 fclose(f);
  467.                 ex = 1;
  468.                 break;
  469.                 }
  470.             }
  471.             }
  472.         else                       // End of plane
  473.             {
  474.             plane_num--;
  475.             x = plane_num * bplin + start_x;
  476.             }
  477.         }
  478.         }
  479.     }
  480.  
  481.     if(p.nplanes != buf->nplanes || p.bitpx != buf->bitpx // if formates are
  482.         || col != 16)
  483.     {                                                  // incompatible
  484.     int src_max_color = s_max_color(p.bitpx, p.nplanes);  // max color in src
  485.     int dest_max_color = getmaxcolor();
  486.     int color_mult = get_color_mult(src_max_color, dest_max_color);  // Simple color filter
  487.     int color_mult_15 = get_color_mult(src_max_color, 15);
  488.     int work_y = 0;                                 // in "new" buffer
  489.     int bound1 = pos.Y / buf->bound_size.Y;
  490.     int bound2 = 0;
  491.     int y = pos.Y - bound1 * buf->bound_size.Y;     // Inside (buf) image
  492.     work_gb->get_bound(0);        // Read src and det bounds
  493.     buf->get_bound(bound1);
  494.     while(1)
  495.         {
  496.         if(work_y == work_gb->bound_size.Y)  // End of (work) bound
  497.         {
  498.         work_y = 0;                      // Prepare to load new (work)
  499.         bound2++;                        // bound
  500.         if(bound2 == (p.y2 - p.y1 + 1) / work_gb->bound_size.Y + 1)
  501.             {                            // Last bound to read
  502.             buf->put_bound(bound1);      // flash the rest and exit
  503.             break;
  504.             }
  505.         work_gb->get_bound(bound2);      // Else - load next bound
  506.         }
  507.         if(y == buf->bound_size.Y)           // End of (buf) bound
  508.         {
  509.         buf->put_bound(bound1);          // Swap modified bound
  510.         y = 0;                           // and prepare to load next
  511.         bound1++;
  512.         buf->get_bound(bound1);          // Load next (buf) bound
  513.         }
  514.  
  515.         int end_y = (bound1 == (pos.Y + p.y2 - p.y1 + 1)
  516.                     / buf->bound_size.Y)
  517.         ? pos.Y + p.y2 - p.y1 + 1 - bound1 * buf->bound_size.Y
  518.         : buf->bound_size.Y;
  519.  
  520.         for(; y < end_y && work_y < work_gb->bound_size.Y;
  521.             y++, work_y++)
  522.         {
  523.         for(int x = pos.X; x < pos.X + p.x2 - p.x1 + 1; x++)
  524.             {
  525.             int pix = image_get_pixel(work_gb->image,
  526.             loc(x - pos.X, work_y), p.bitpx, p.nplanes);
  527.             if(dest_max_color < src_max_color)
  528.             {
  529.             if(src_max_color <= 15)
  530.                 pix = (bw_pix(pix * color_mult_15, x,
  531.                  y + bound1 * buf->bound_size.Y))
  532.                  ? pix / color_mult
  533.                  : dest_max_color - pix / color_mult;
  534.             else
  535.                 pix = (bw_pix(pix / color_mult_15, x,
  536.                  y + bound1 * buf->bound_size.Y))
  537.                  ? pix / color_mult
  538.                  : dest_max_color - pix / color_mult;
  539.             }
  540.             else
  541.                 if(dest_max_color > src_max_color)
  542.                 pix = pix * color_mult;
  543.  
  544.                     if(pix != col)
  545.                         image_put_pixel(buf->image, loc(x, y), pix,
  546.                 buf->bitpx, buf->nplanes);
  547.             }
  548.         }
  549.         if(bound1 == (pos.Y + p.y2 - p.y1 + 1) / buf->bound_size.Y)
  550.         {
  551.         buf->put_bound(bound1);
  552.         break;
  553.         }
  554.         }
  555.     work_gb->b_close();
  556.     delete work_gb;
  557.     }
  558.     return 1;
  559.     }
  560. ///////////////////////////
  561. inline void pcx_put_char(uchar count, uchar ch, FILE* f)
  562.     {
  563.     if(count > 1 || (0xC0 == (0xC0 & ch)))
  564.     fputc(count | 128 | 64, f);   // Write counter
  565.     fputc(ch, f);                     // Write pattern
  566.     }
  567. //////////////////////////
  568. void GrafBuffer::pcx_buffer_file(rect src, char* name)
  569.     {
  570.     if(src.right() >= bound_size.X)                   // If any mistake
  571.     return;
  572.  
  573.     FILE* f = fopen(name, "w+b");                      // Open target file
  574.     pcxheader p;                                           // Put header
  575.     put_pcx_header(f, &p, loc(src.width(), src.height())); // of target file
  576.  
  577.     pcxheader work;                                   // The pseudo-header
  578.     work.bitpx = 1;                                  // contains information
  579.     work.nplanes = 4;                                // about current
  580.     work.x1 = 0;                                     // graphics buffer
  581.     work.y1 = 0;
  582.     work.x2 = bound_size.X - 1;
  583.     work.y2 = bound_size.Y - 1;
  584.     work.bplin = (bound_size.X + 7) >> 3;
  585.  
  586.     int start_bound = src.origin.Y / bound_size.Y;    // Start buffer bound
  587.     int end_bound = src.corner.Y / bound_size.Y + 1;
  588.     int plane_num = 3;                  // Number of current plane,
  589.                                         // work.nplanes - 1 == 3 for VGA/EGA
  590.     int w_data = work.nplanes * work.bplin; // Length of image line, bytes
  591.     uchar count = 1;                        // PCX counter
  592.  
  593.     int start_x = src.origin.X / 8;    // Between beginning of plane and
  594.                                        // beginning of rect, bytes
  595.     int src_bytes = src.width() / 8;   // Significant bytes in src scan line
  596.     int x = start_x + plane_num * work.bplin;  // Start x in current plane of
  597.                                                // source rectangle
  598.     int i = start_bound;                       // Counter of biunds
  599.     int y = src.origin.Y - bound_size.Y * i;   // Start y in current bound
  600.  
  601.     get_bound(i);                                     // Read bound
  602.     unsigned char ch = image->data[x + w_data * y];   // Get start char
  603.     int plane_end = x + src_bytes;                    // End of current plane
  604.  
  605.     while(1)                             // The main cycle
  606.     {
  607.     x++;                             // Move the pointer in image
  608.     if(x == plane_end)
  609.         {                             // End of scan line or end of plane.
  610.         if(plane_num != 0)           // If it is end of plane,
  611.         {                        // not of scan line.
  612.         plane_num--;             // 3-2-1-0 in BGI == 0-1-2-3 in PCX
  613.         x = plane_num * work.bplin + start_x;  // Start x in
  614.         plane_end -= work.bplin;               // new plane.
  615.         }
  616.         else                         // It is end of scan line
  617.         {
  618.         if(i < end_bound)        // Not last bound.
  619.             {
  620.             plane_num = 3;       // work.nplanes - 1;
  621.             x = start_x + 3 * work.bplin;  // Start x in 4th plane
  622.             plane_end = x + src_bytes; // End of 4th plane
  623.             if(y + 1 == bound_size.Y)      // If bottom of bound
  624.             {
  625.             i++;                      // Go to next bound
  626.             y = 0;
  627.             get_bound(i);             // Read new bound
  628.             }
  629.             else
  630.             y++;                      // Continue with this bound
  631. /*  The following code, marked !! is absolutely unnecessary and ineffective.
  632.     But Painbrush use stop-on-the-scan-line technology. I don't know why.
  633.     This code is compatible with Paintbrush.
  634. */
  635.             pcx_put_char(count, ch, f);          // !!
  636.             count = 0;                           // !!
  637.             ch = image->data[x + w_data * y];    // !!
  638.  
  639.             }
  640.         else                              // Last bound
  641.             {
  642.             pcx_put_char(count, ch, f);   // Write counter last time
  643.             break;                        // exit the loop
  644.             }
  645.         }
  646.         }
  647.  
  648.     if(ch == image->data[x + w_data * y])  // If current data is the same
  649.         {                                  // as previous, keeped in ch
  650.         if(count == 63)
  651.         {
  652.                 pcx_put_char(count, ch, f);
  653.             count = 1;
  654.         }
  655.             else
  656.         count++;
  657.         }
  658.     else                                  // New data value
  659.         {
  660.         pcx_put_char(count, ch, f);       // Flash old counter
  661.         count = 1;                        // Start new counter
  662.         ch = image->data[x + w_data * y]; // Read next
  663.         }
  664.     }
  665.     fclose(f);
  666.     }
  667. /////////////////////////
  668. /*
  669. void main()
  670.     {
  671.     int gdriver = DETECT, gmode;
  672.     initgraph(&gdriver, &gmode, "");
  673.  
  674.     GrafBuffer* g = new GrafBuffer(loc(1001, 1000), "work.buf",
  675.                    rect(0, 0, 600, 400));
  676.     g->b_open();
  677.     g->clear();
  678.  
  679.     char* name = strdup("c:\\myprog\\sova.pcx");
  680.     pcx_file_buffer(g, loc(0, 0), name);//, LIGHTGRAY);
  681.     g->buffer_screen();
  682.  
  683.     g->pcx_buffer_file(rect(64, 40, 191, 300), "work.pcx");
  684.  
  685.     pcx_file_buffer(g, loc(0, 0), "work.pcx");
  686.     g->buffer_screen();
  687.  
  688.     g->b_close();
  689.     delete g;
  690.     delete name;
  691.  
  692.     closegraph();
  693.     }
  694. */
  695.  
  696.